import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
import { Spin } from 'antd';
import ReactMarkdown from 'react-markdown';
import {  Input, Button, List, Avatar, Typography, message, Popover, Space, Tooltip, Collapse, Modal, Tabs, Switch, Dropdown } from 'antd';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
import { CopyOutlined, CheckOutlined, LoadingOutlined, CaretRightOutlined, DownloadOutlined, ClockCircleOutlined, ZoomInOutlined, SettingOutlined } from '@ant-design/icons';
import {
  SendOutlined,
  UserOutlined,
  RobotOutlined,
  TranslationOutlined,
  ReadOutlined,
  BulbOutlined,
  BugOutlined,
  CheckSquareOutlined,
  QuestionCircleOutlined,
  ExclamationCircleOutlined,
  ReloadOutlined,
  StopOutlined,
  ApiOutlined,
  CheckCircleOutlined,
  PaperClipOutlined,
  CloseOutlined,
  MoreOutlined
} from '@ant-design/icons';
import ImageViewer, { useImagePreview } from './ImageViewer';
import type { ImageInfo } from './ImageViewer';

// 扩展Window接口，添加triggerImagePreview属性
declare global {
  interface Window {
    triggerImagePreview?: (src: string) => void;
  }
}

// Markdown 解析和渲染相关库
import remarkGfm from 'remark-gfm';           // GitHub Flavored Markdown 支持（表格、删除线、任务列表等）
import rehypeRaw from 'rehype-raw';           // 允许在 Markdown 中渲染原始 HTML 标签
import mermaid from 'mermaid';                // 流程图和图表渲染库
import remarkMath from 'remark-math';         // 数学公式语法解析
import rehypeKatex from 'rehype-katex';       // 数学公式渲染（使用 KaTeX 引擎）
import 'katex/dist/katex.min.css';


const API_KEY = "app-YqGr7k9juqzAWeq2FIH5uUue";
const API_URL = "https://api.dify.ai/v1";

interface WorkflowNode {
  id: string;
  title: string;
  status: 'waiting' | 'running' | 'succeeded' | 'failed' | 'stopped' | string;
  elapsedTime?: number | string;
  startTime?: number;
  index?: number; // 添加节点执行顺序
}

interface Message {
  role: 'user' | 'assistant';
  content: string;
  workflow?: {
    taskId: string;
    nodes: WorkflowNode[];
  };
  completed?: boolean;
  tools?: ToolCallProps[];
  files?: Array<{ id: string, name: string, url?: string, type?: string, local?: boolean }>;
  toolPositions?: Record<string, number>; // 记录工具调用在内容中的位置
}

// MCP服务器配置接口
interface MCPServer {
  name: string;
  url: string;
  type: string;
  status?: 'connected' | 'connecting' | 'disconnected';
  disabled?: boolean;
}

interface AiChatProps {
  visible: boolean;
  onClose: () => void;
  problemDescription?: string;  // 包含样例输入输出、时间内存限制等完整的问题描述
  studentCode?: string;
  programmingLanguage?: string;
  errorMessage?: string;
  output?: string;  // 添加运行结果
  tags?: string;  // 问题标签（字符串）

}

interface AiButton {
  key: string;
  icon: React.ReactNode;
  text: string;
  prompt: (props: AiChatProps) => string;
}

const aiButtons: AiButton[] = [
  {
    key: 'translate',
    icon: <TranslationOutlined />,
    text: '题目翻译',
    prompt: () => '题目翻译'
  },
  {
    key: 'analyze',
    icon: <ReadOutlined />,
    text: '题目解读',
    prompt: () => '题目解读'
  },
  {
    key: 'guide',
    icon: <BulbOutlined />,
    text: '思路指导',
    prompt: () => '思路指导'
  },
  {
    key: 'debug',
    icon: <BugOutlined />,
    text: '代码纠错',
    prompt: () => '代码纠错'
  },
  {
    key: 'evaluate',
    icon: <CheckSquareOutlined />,
    text: '质量评估',
    prompt: () => '质量评估'
  },
  {
    key: 'error-analyze',
    icon: <ExclamationCircleOutlined />,
    text: '报错分析',
    prompt: () => '报错分析'
  },
  {
    key: 'test-report',
    icon: <CheckCircleOutlined />,
    text: '测试报告',
    prompt: () => 'test'
  },
  {
    key: 'ask',
    icon: <QuestionCircleOutlined />,
    text: '直接询问',
    prompt: () => ''
  }
];

// 创建一个全局缓存来存储已渲染的图表
// 这样即使组件重新挂载也能复用已渲染的图表
const mermaidCache = new Map<string, { svg: string, error: string | null }>();

// 创建一个全局缓存来保存图表的展开状态
const mermaidExpandedStateCache = new Map<string, boolean>();

// 全局静态加载组件，避免重新创建
const MermaidLoadingComponent = (
  <div style={{
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
    padding: '20px 0',
    minHeight: '120px'
  }}>
    <Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} tip="流程图渲染中...">
          <div style={{ minHeight: '100px' }} />
        </Spin>
  </div>
);

// 创建一个不变的加载中占位符，确保在流式输出时不会频繁重渲染
const StaticMermaidPlaceholder = React.memo(() => {
  return (
    <div style={{
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center',
      padding: '20px 0',
      minHeight: '120px',
      backgroundColor: '#f8f9fa',
      border: '1px dashed #e9ecef',
      borderRadius: '4px',
      color: '#6c757d'
    }}>
      <Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} tip="准备渲染流程图...">
          <div style={{ minHeight: '100px' }} />
        </Spin>
    </div>
  );
});

// 检查mermaid代码块是否完整
const isMermaidCodeComplete = (code: string, originalMessage?: string): boolean => {
  if (!code || code.trim().length < 10) return false;

  // 检查原始消息是否已经包含结束标记```
  // 这是强制要求：必须以```结尾
  if (originalMessage) {
    // 需要找到当前代码块在原始消息中的位置
    const codeInMessage = originalMessage.indexOf(code);
    if (codeInMessage === -1) return false;

    // 检查代码块后是否紧跟着```
    const textAfterCode = originalMessage.substring(codeInMessage + code.length);
    const hasClosingFence = textAfterCode.trim().startsWith('```') ||
      textAfterCode.includes('\n```') ||
      originalMessage.endsWith('```');

    // 如果没有找到结束标记，则不渲染
    if (!hasClosingFence) return false;
  } else {
    // 没有原始消息无法判断，要求消息完成
    return false;
  }

  // 检查是否包含基本的mermaid语法元素
  const trimmedCode = code.trim();

  // 检查是否有基本的图表类型定义
  const hasGraphDefinition =
    trimmedCode.includes('graph ') ||
    trimmedCode.includes('flowchart ') ||
    trimmedCode.includes('sequenceDiagram') ||
    trimmedCode.includes('classDiagram') ||
    trimmedCode.includes('stateDiagram') ||
    trimmedCode.includes('erDiagram') ||
    trimmedCode.includes('journey') ||
    trimmedCode.includes('gantt') ||
    trimmedCode.includes('pie');

  // 检查是否有结束标记或关系定义
  const hasRelationships =
    trimmedCode.includes('-->') ||
    trimmedCode.includes('==>') ||
    trimmedCode.includes('-->') ||
    trimmedCode.includes('---|') ||
    trimmedCode.includes('--o') ||
    trimmedCode.includes('--x') ||
    (trimmedCode.includes('->') && !!trimmedCode.match(/[A-Za-z0-9]->/));

  // 检查是否有足够的行数和结构
  const lines = trimmedCode.split('\n').filter(line => line.trim().length > 0);
  const hasEnoughStructure = lines.length >= 2;

  return hasGraphDefinition && (hasRelationships || hasEnoughStructure);
};

// 独立的Mermaid图表组件，完全分离渲染逻辑
const MermaidDiagram = React.memo(({ code, messageCompleted, originalMessage }: {
  code: string;
  messageCompleted?: boolean;
  originalMessage?: string;
}) => {
  // 为每个图表生成稳定的key
  const codeKey = useMemo(() => {
    // 使用代码内容作为缓存键
    return code.trim();
  }, [code]);

  // 从缓存获取或初始化状态
  const [renderState, setRenderState] = useState(() => {
    if (mermaidCache.has(codeKey)) {
      const cached = mermaidCache.get(codeKey)!;
      return {
        svg: cached.svg,
        error: cached.error,
        isRendering: false,
        hasRendered: !!cached.svg || !!cached.error
      };
    }
    return { svg: '', error: null, isRendering: false, hasRendered: false };
  });

  const [copied, setCopied] = useState(false);
  // 使用useRef存储expanded状态，而不是useState，避免重渲染时状态丢失
  const expandedRef = useRef(false);
  // 从全局缓存中恢复展开状态
  const [expanded, setExpanded] = useState(() => {
    return mermaidExpandedStateCache.has(codeKey)
      ? mermaidExpandedStateCache.get(codeKey)!
      : false;
  });
  const mermaidId = useRef(`mermaid-${Math.floor(Math.random() * 1000000)}`);
  const containerRef = useRef<HTMLDivElement>(null);
  const renderAttemptedRef = useRef(false);

  // 判断代码是否完整可渲染
  const isCodeComplete = useMemo(() => isMermaidCodeComplete(code, originalMessage), [code, originalMessage]);

  // 复制到剪贴板
  const copyToClipboard = useCallback(() => {
    navigator.clipboard.writeText(code);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  }, [code]);

  // 下载SVG图表
  const downloadSvg = useCallback(() => {
    if (!renderState.svg) return;

    try {
      const svgBlob = new Blob([renderState.svg], { type: 'image/svg+xml' });
      const url = URL.createObjectURL(svgBlob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `flowchart-${new Date().toISOString().slice(0, 10)}.svg`;
      document.body.appendChild(a);
      a.click();

      setTimeout(() => {
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
      }, 100);
    } catch (err) {
      console.error('下载SVG失败:', err);
      message.error('下载失败');
    }
  }, [renderState.svg]);

  // 清理错误元素
  const cleanupErrorElements = useCallback(() => {
    try {
      document.querySelectorAll('.mermaid').forEach(el => {
        if (el.innerHTML.includes('Syntax error in text') || !el.innerHTML.trim()) {
          el.remove();
        }
      });

      document.querySelectorAll('[id^="dmermaid-"]').forEach(el => {
        if (!el.innerHTML.trim()) {
          el.remove();
        }
      });

      document.querySelectorAll('svg[aria-roledescription="error"]').forEach(el => {
        el.remove();
      });
    } catch (err) {
      console.error('清理错误元素失败:', err);
    }
  }, []);

  // 切换展开/折叠状态
  const toggleExpand = useCallback(() => {
    expandedRef.current = !expandedRef.current;
    setExpanded(expandedRef.current);
    // 更新全局缓存中的展开状态
    mermaidExpandedStateCache.set(codeKey, expandedRef.current);
  }, [codeKey]);

  // 同步expanded状态到ref，确保我们始终使用最新值
  useEffect(() => {
    expandedRef.current = expanded;
    // 在状态变化时也更新全局缓存
    mermaidExpandedStateCache.set(codeKey, expanded);
  }, [expanded, codeKey]);

  // 防止滚动时意外收缩
  useEffect(() => {
    // 只在展开状态下添加滚动事件监听
    if (expanded && containerRef.current) {
      const handleWheel = (e: WheelEvent) => {
        // 阻止冒泡，防止外部容器接收到滚动事件
        e.stopPropagation();
      };

      const container = containerRef.current;
      container.addEventListener('wheel', handleWheel, { passive: false });

      return () => {
        container.removeEventListener('wheel', handleWheel);
      };
    }
  }, [expanded]);

  // 渲染Mermaid图表
  const renderMermaid = useCallback(async () => {
    // 如果已经渲染完成或正在渲染中，则不重复渲染
    if (renderState.hasRendered || renderState.isRendering) {
      return;
    }

    // 如果代码为空，不进行渲染
    if (!code.trim()) {
      return;
    }

    // 标记为正在渲染中
    setRenderState(prev => ({ ...prev, isRendering: true }));

    try {
      // 清理已存在的元素
      document.querySelectorAll(`[id^="d${mermaidId.current}"]`).forEach(el => el.remove());
      document.querySelectorAll(`#${mermaidId.current}`).forEach(el => el.remove());

      // 配置mermaid
      mermaid.initialize({
        startOnLoad: false,
        theme: 'default',
        securityLevel: 'loose',
        logLevel: 'error',
        fontFamily: 'monospace',
        flowchart: {
          htmlLabels: true,
          curve: 'linear',
          useMaxWidth: true
        },
        er: {
          useMaxWidth: true
        },
        sequence: {
          useMaxWidth: true,
          noteFontWeight: 'normal'
        }
      });

      // 格式化代码
      let fixedCode = code.trim();
      if (!fixedCode.includes('graph ') && !fixedCode.includes('flowchart ')) {
        if (fixedCode.match(/^[A-Z][^{]+->/)) {
          fixedCode = 'graph TD\n' + fixedCode;
        }
      }

      // 渲染图表
      const { svg } = await mermaid.render(mermaidId.current, fixedCode);

      // 更新状态和缓存
      setRenderState({ svg, error: null, isRendering: false, hasRendered: true });
      mermaidCache.set(codeKey, { svg, error: null });

      // 清理残留元素
      cleanupErrorElements();
    } catch (err) {
      console.error('Mermaid rendering error:', err);

      // 更新错误状态和缓存
      const errorMsg = '图表渲染失败，请检查语法';
      setRenderState({ error: errorMsg, svg: '', isRendering: false, hasRendered: true });
      mermaidCache.set(codeKey, { svg: '', error: errorMsg });

      // 清理残留元素
      cleanupErrorElements();
    }
  }, [code, codeKey, renderState.hasRendered, renderState.isRendering, cleanupErrorElements]);

  // 在组件挂载时尝试渲染
  useEffect(() => {
    // 当组件挂载且未尝试渲染过，则尝试渲染
    if (!renderAttemptedRef.current) {
      renderAttemptedRef.current = true;

      // 如果已经在缓存中并已渲染，则不再重复渲染
      if (renderState.hasRendered) {
        return;
      }

      // 判断是否应该立即渲染：如果代码完整或消息已完成，则渲染
      if (messageCompleted || isCodeComplete) {
        renderMermaid();
      }
    }
  }, [renderMermaid, renderState.hasRendered, messageCompleted, isCodeComplete]);

  // 在代码变化或消息完成时触发渲染
  useEffect(() => {
    // 只有未渲染过且未在渲染中时才尝试渲染
    if (!renderState.hasRendered && !renderState.isRendering) {
      // 如果代码完整或消息已完成，则渲染
      if (messageCompleted || isCodeComplete) {
        renderMermaid();
      }
    } else if (messageCompleted && renderState.isRendering) {
      // 如果消息已完成但图表还在渲染中，继续等待渲染完成
      // 不再取消渲染
    }
  }, [messageCompleted, isCodeComplete, renderState.hasRendered, renderState.isRendering, renderMermaid, codeKey]);

  // 组件卸载时清理
  useEffect(() => {
    return () => {
      cleanupErrorElements();
    };
  }, [cleanupErrorElements]);

  // 如果消息未完成且代码不完整，显示静态占位符
  if (!messageCompleted && !isCodeComplete) {
    return (
      <div ref={containerRef} style={{ position: 'relative', marginBottom: '16px' }}>
        <div style={{
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          padding: '4px 8px',
          backgroundColor: '#343a40',
          color: '#e9ecef',
          borderTopLeftRadius: '6px',
          borderTopRightRadius: '6px',
          fontSize: '12px'
        }}>
          <span>mermaid</span>
          <div>
            <Tooltip title="复制代码">
              <Button
                type="text"
                size="small"
                icon={<CopyOutlined style={{ color: '#e9ecef' }} />}
                onClick={copyToClipboard}
                style={{
                  padding: '0 4px',
                  height: '22px',
                  backgroundColor: 'transparent'
                }}
              />
            </Tooltip>
          </div>
        </div>
        <div style={{
          padding: '16px',
          backgroundColor: '#f8f9fa',
          borderBottomLeftRadius: '6px',
          borderBottomRightRadius: '6px',
          border: '1px solid #e9ecef',
          borderTop: 'none',
          overflow: 'auto',
          maxHeight: '200px',
          minHeight: '80px'
        }}>
          <StaticMermaidPlaceholder />
        </div>
      </div>
    );
  }

  // 内容渲染逻辑
  const contentRender = useMemo(() => {
    if (renderState.error) {
      return <div style={{ color: 'red' }}>{renderState.error}</div>;
    }

    if (renderState.svg) {
      return (
        <div
          dangerouslySetInnerHTML={{ __html: renderState.svg }}
        />
      );
    }

    // 统一显示加载组件，不使用占位符
    return MermaidLoadingComponent;
  }, [renderState.error, renderState.svg]);

  return (
    <div ref={containerRef} style={{ position: 'relative', marginBottom: '16px' }}>
      <div style={{
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
        padding: '4px 8px',
        backgroundColor: '#343a40',
        color: '#e9ecef',
        borderTopLeftRadius: '6px',
        borderTopRightRadius: '6px',
        fontSize: '12px'
      }}>
        <span>mermaid</span>
        <div>
          <Tooltip title={expanded ? "收起图表" : "展开图表"}>
            <Button
              type="text"
              size="small"
              icon={expanded ?
                <CaretRightOutlined rotate={90} style={{ color: '#e9ecef' }} /> :
                <CaretRightOutlined style={{ color: '#e9ecef' }} />
              }
              onClick={toggleExpand}
              style={{
                padding: '0 4px',
                height: '22px',
                backgroundColor: 'transparent',
                marginRight: '4px'
              }}
            />
          </Tooltip>
          {renderState.svg && (
            <Tooltip title="下载SVG">
              <Button
                type="text"
                size="small"
                icon={<DownloadOutlined style={{ color: '#e9ecef' }} />}
                onClick={downloadSvg}
                style={{
                  padding: '0 4px',
                  height: '22px',
                  backgroundColor: 'transparent',
                  marginRight: '4px'
                }}
              />
            </Tooltip>
          )}
          <Tooltip title={copied ? "已复制！" : "复制代码"}>
            <Button
              type="text"
              size="small"
              icon={copied ? <CheckOutlined style={{ color: '#52c41a' }} /> : <CopyOutlined style={{ color: '#e9ecef' }} />}
              onClick={copyToClipboard}
              style={{
                padding: '0 4px',
                height: '22px',
                backgroundColor: 'transparent'
              }}
            />
          </Tooltip>
        </div>
      </div>
      <div style={{
        padding: '16px',
        backgroundColor: '#f8f9fa',
        borderBottomLeftRadius: '6px',
        borderBottomRightRadius: '6px',
        border: '1px solid #e9ecef',
        borderTop: 'none',
        overflow: 'auto',
        maxHeight: expanded ? '100%' : '200px',
        minHeight: '80px',
        transition: 'max-height 0.3s ease'
      }}>
        {contentRender}
      </div>
    </div>
  );
});

// 使用React.memo包装CodeBlockWithCopy组件，避免不必要的重新渲染
const CodeBlockWithCopy = React.memo(({ children, language, messageCompleted, originalMessage }: {
  children: React.ReactNode;
  language: string;
  messageCompleted?: boolean;
  originalMessage?: string;
}) => {
  const [copied, setCopied] = useState(false);
  const code = String(children).replace(/\n$/, '');

  const copyToClipboard = useCallback(() => {
    navigator.clipboard.writeText(code);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  }, [code]);

  // 如果是mermaid代码块，使用MermaidDiagram组件
  if (language === 'mermaid') {
    return <MermaidDiagram code={code} messageCompleted={messageCompleted} originalMessage={originalMessage} />;
  }

  return (
    <div style={{ position: 'relative', marginBottom: '16px' }}>
      <div style={{
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
        padding: '4px 8px',
        backgroundColor: '#343a40',
        color: '#e9ecef',
        borderTopLeftRadius: '6px',
        borderTopRightRadius: '6px',
        fontSize: '12px'
      }}>
        <span>{language || 'text'}</span>
        <Tooltip title={copied ? "已复制！" : "复制代码"}>
          <Button
            type="text"
            size="small"
            icon={copied ? <CheckOutlined style={{ color: '#52c41a' }} /> : <CopyOutlined style={{ color: '#e9ecef' }} />}
            onClick={copyToClipboard}
            style={{
              padding: '0 4px',
              height: '22px',
              backgroundColor: 'transparent'
            }}
          />
        </Tooltip>
      </div>
      <SyntaxHighlighter
        language={language || 'text'}
        style={vscDarkPlus}
        customStyle={{
          margin: 0,
          borderTopLeftRadius: 0,
          borderTopRightRadius: 0,
          borderBottomLeftRadius: '6px',
          borderBottomRightRadius: '6px',
          maxWidth: '100%',
          overflowX: 'auto',
        }}
      >
        {code}
      </SyntaxHighlighter>
    </div>
  );
});

// 工作流进度组件
const WorkflowProcess: React.FC<{ nodes: WorkflowNode[]; completed?: boolean; expanded: boolean; onToggle: () => void }> = ({ nodes, completed = false, expanded, onToggle }) => {
  // 获取整体工作流状态
  const getWorkflowStatus = () => {
    // 如果没有节点，返回默认状态
    if (nodes.length === 0) {
      return completed ? 'succeeded' : 'running';
    }

    // 如果消息尚未完成，检查是否有运行中的节点
    if (!completed) {
      const hasRunning = nodes.some(node => node.status === 'running');
      if (hasRunning) {
        return 'running';
      }
    }

    // 检查是否有任何节点失败
    const hasFailed = nodes.some(node => node.status === 'failed');
    if (hasFailed) {
      return 'failed';
    }

    // 检查是否有任何节点被停止
    const hasStopped = nodes.some(node => node.status === 'stopped');
    if (hasStopped) {
      return 'stopped';
    }

    // 所有节点都成功完成
    return 'succeeded';
  };

  const getStatusIcon = (status: string) => {
    switch (status) {
      case 'running':
        return <LoadingOutlined style={{ color: '#1890ff' }} />;
      case 'succeeded':
        return <CheckOutlined style={{ color: '#52c41a' }} />;
      case 'failed':
        return <ExclamationCircleOutlined style={{ color: '#f5222d' }} />;
      case 'stopped':
        return <StopOutlined style={{ color: '#faad14' }} />;
      case 'waiting':
        return <ClockCircleOutlined style={{ color: '#8c8c8c' }} />;
      default:
        return null;
    }
  };

  return (
    <div className="workflow-process" style={{ marginBottom: '8px', backgroundColor: '#f5f5f5', borderRadius: '6px' }}>
      <div
        className="workflow-header"
        style={{
          padding: '4px 10px',
          backgroundColor: '#e6e6e6',
          borderRadius: '6px',
          cursor: 'pointer',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'space-between',
          height: '26px'
        }}
        onClick={onToggle}
      >
        <div style={{ display: 'flex', alignItems: 'center' }}>
          {getStatusIcon(getWorkflowStatus())}
          <span style={{ fontSize: '12px', marginLeft: '6px' }}>Workflow Process</span>
        </div>
        <CaretRightOutlined
          style={{
            transform: expanded ? 'rotate(90deg)' : 'rotate(0)',
            transition: 'transform 0.3s',
            fontSize: '12px'
          }}
        />
      </div>

      {expanded && (
        <div style={{ padding: '6px 10px', borderLeft: '1px solid #f0f0f0' }}>
          {[...nodes]
            // 按index属性排序，如果没有index则放在后面
            .sort((a, b) => {
              if (a.index !== undefined && b.index !== undefined) {
                return a.index - b.index;
              } else if (a.index !== undefined) {
                return -1;
              } else if (b.index !== undefined) {
                return 1;
              }
              return 0;
            })
            .map((node, displayIndex) => (
              <div
                key={node.id || displayIndex}
                style={{
                  display: 'flex',
                  justifyContent: 'space-between',
                  margin: '2px 0',
                  backgroundColor: '#ffffff',
                  borderRadius: '4px',
                  padding: '4px 8px',
                  height: '24px',
                  fontSize: '12px',
                  alignItems: 'center',
                  borderBottom: displayIndex === nodes.length - 1 ? 'none' : '1px solid #f0f0f0'
                }}
              >
                <div style={{ display: 'flex', alignItems: 'center' }}>
                  <span style={{
                    width: '18px',
                    height: '18px',
                    borderRadius: '4px',
                    backgroundColor: '#e6f7ff',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    marginRight: '6px',
                    fontSize: '11px'
                  }}>
                    {node.index !== undefined ? node.index : displayIndex + 1}
                  </span>
                  <span style={{ fontSize: '12px' }}>{node.title}</span>
                </div>
                <div style={{ display: 'flex', alignItems: 'center' }}>
                  {node.elapsedTime && (
                    <span style={{ marginRight: '6px', color: '#999', fontSize: '11px' }}>
                      {typeof node.elapsedTime === 'number'
                        ? `${node.elapsedTime.toFixed(3)} s`
                        : node.elapsedTime}
                    </span>
                  )}
                  {getStatusIcon(node.status)}
                </div>
              </div>
            ))}
        </div>
      )}
    </div>
  );
};

// 工具调用标签组件
interface ToolCallProps {
  label: string;
  status: 'start' | 'success' | 'error' | string;
  icon?: string;
  elapsedTime?: number;
  position?: number; // 添加位置索引，用于确定标签显示位置
}

const ToolCallTag: React.FC<ToolCallProps> = ({ label, status, elapsedTime }) => {
  // 从 "CALL xxx" 格式中提取工具名称
  const toolName = label.startsWith('CALL ') ? label.substring(5) : label;

  // 根据状态确定图标和颜色
  const getStatusIcon = () => {
    switch (status) {
      case 'start':
        return <LoadingOutlined style={{ color: '#1890ff' }} />;
      case 'success':
        return <CheckCircleOutlined style={{ color: '#52c41a' }} />;
      case 'error':
        return <ExclamationCircleOutlined style={{ color: '#f5222d' }} />;
      default:
        return <ApiOutlined style={{ color: '#1890ff' }} />;
    }
  };

  // 根据状态确定背景色
  const getTagColor = () => {
    switch (status) {
      case 'start':
        return '#e6f7ff';
      case 'success':
        return '#f6ffed';
      case 'error':
        return '#fff2f0';
      default:
        return '#f0f2f5';
    }
  };

  return (
    <div style={{
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'space-between',
      padding: '4px 8px',
      borderRadius: '4px',
      backgroundColor: getTagColor(),
      margin: '4px 0',
      fontSize: '12px',
      color: 'rgba(0, 0, 0, 0.65)',
      border: '1px solid #e8e8e8',
      width: '100%'
    }}>
      <div style={{ display: 'flex', alignItems: 'center' }}>
        <ApiOutlined style={{ marginRight: 6 }} />
        <span>{toolName}</span>
      </div>
      <div style={{ display: 'flex', alignItems: 'center' }}>
        {getStatusIcon()}
        {elapsedTime !== undefined && status === 'success' && (
          <span style={{ marginLeft: 6, color: '#8c8c8c', fontSize: '11px' }}>
            {elapsedTime.toFixed(2)}s
          </span>
        )}
      </div>
    </div>
  );
};

// 使用React.memo创建一个缓存的消息渲染组件
const MemoizedMessageContent = React.memo(
  ({ message, openPreview, isLatestAiMessage }: {
    message: Message;
    openPreview: (images: ImageInfo[], index?: number) => void;
    isLatestAiMessage: boolean
  }): React.ReactNode => {
    return renderMessageContent(message, openPreview, isLatestAiMessage);
  },
  (prevProps, nextProps) => {
    // 如果消息内容、完成状态或工具调用没有变化，不重新渲染
    return (
      prevProps.message.content === nextProps.message.content &&
      prevProps.message.completed === nextProps.message.completed &&
      prevProps.isLatestAiMessage === nextProps.isLatestAiMessage &&
      JSON.stringify(prevProps.message.tools) === JSON.stringify(nextProps.message.tools) &&
      JSON.stringify(prevProps.message.toolPositions) === JSON.stringify(nextProps.message.toolPositions)
    );
  }
);

// 定义renderMessageContent函数，需要传入openPreview函数
const renderMessageContent = (message: Message, openPreview: (images: ImageInfo[], index?: number) => void, isLatestAiMessage: boolean = false) => {
  if (!message.content) {
    // 如果消息已完成但没有内容，不显示加载图标
    if (message.completed) {
      return null;
    }
    return <Spin />;
  }

  if (message.role === 'user') {
    // 处理包含HTML img标签或markdown图片的消息
    if (message.content.includes('<img') || message.content.includes('![')) {
      // 使用正则表达式给图片添加额外的样式和点击事件
      let processedContent = message.content;

      // 使用正则表达式匹配所有img标签
      const imgRegex = /<img[^>]+src="([^"]+)"[^>]*>/g;

      // 收集所有图片URL
      const imgUrls: string[] = [];
      let match;
      while ((match = imgRegex.exec(processedContent)) !== null) {
        imgUrls.push(match[1]);
      }

      // 替换img标签，添加点击事件和样式
      processedContent = processedContent.replace(
        imgRegex,
        (match, src) => {
          return match.replace(
            '<img',
            `<img onclick="window.triggerImagePreview('${src}')" style="cursor:zoom-in; max-width:100%; max-height:200px; object-fit:contain; border-radius:4px; display:block; border:1px solid #eaeaea;"`
          );
        }
      );

      // 如果是用户消息，调整图片的样式，确保在蓝色背景上也能正常显示
      processedContent = processedContent.replace(
        /<div style="margin: 10px 0;">/g,
        '<div style="margin: 10px 0; border-radius: 8px; padding: 6px;">'
      );

      // 使用dangerouslySetInnerHTML直接渲染HTML内容
      return (
        <div
          dangerouslySetInnerHTML={{ __html: processedContent }}
          style={{
            wordBreak: 'break-word',
            overflowWrap: 'break-word',
            width: '100%'
          }}
        />
      );
    }

    return message.content;
  }

  // 处理助手消息，提取工具调用
  const toolCalls = message.tools?.filter(tool => tool.label.startsWith('CALL ')) || [];

  // 将工具调用直接嵌入到内容中
  const renderContentWithTools = () => {
    // 性能优化：如果不是最新的AI消息且有复杂内容，使用简化渲染方式
    if (!isLatestAiMessage && message.content.length > 500 && message.completed) {
      // 对于长消息和非最新消息，使用简化的渲染方式
      return (
        <ReactMarkdown
          remarkPlugins={[remarkGfm, remarkMath]}
          rehypePlugins={[rehypeRaw, rehypeKatex]}
          components={markdownComponents(message.completed, message.content)}
        >
          {message.content}
        </ReactMarkdown>
      );
    }

    if (!toolCalls.length) {
      // 没有工具调用，直接渲染Markdown
      return (
        <ReactMarkdown
          remarkPlugins={[remarkGfm, remarkMath]}
          rehypePlugins={[rehypeRaw, rehypeKatex]}
          components={markdownComponents(message.completed, message.content)}
        >
          {message.content}
        </ReactMarkdown>
      );
    }

    // 基于toolPositions和content构建包含工具调用的内容
    const toolPositions = message.toolPositions || {};
    const sortedPositions = Object.entries(toolPositions)
      .sort((a, b) => parseInt(a[1] as any) - parseInt(b[1] as any))
      .map(([toolName, position]) => ({ toolName, position: position as number }));

    const result: React.ReactElement[] = [];
    let lastPosition = 0;

    // 按位置顺序插入工具调用组件
    sortedPositions.forEach(({ toolName, position }) => {
      // 添加位置之前的文本内容
      if (position > lastPosition) {
        const textSegment = message.content.substring(lastPosition, position);
        if (textSegment.trim()) {
          result.push(
            <ReactMarkdown
              key={`text-${lastPosition}`}
              remarkPlugins={[remarkGfm, remarkMath]}
              rehypePlugins={[rehypeRaw, rehypeKatex]}
              components={markdownComponents(message.completed, message.content)}
            >
              {textSegment}
            </ReactMarkdown>
          );
        }
      }

      // 查找对应的工具调用
      const tool = toolCalls.find(t =>
        t.label.replace('CALL ', '').toLowerCase() === toolName.toLowerCase()
      );

      if (tool) {
        // 添加工具调用标签
        result.push(
          <ToolCallTag
            key={`tool-${position}`}
            label={tool.label}
            status={tool.status}
            elapsedTime={tool.elapsedTime}
          />
        );
      }

      lastPosition = position;
    });

    // 添加最后一段文本
    if (lastPosition < message.content.length) {
      const textSegment = message.content.substring(lastPosition);
      if (textSegment.trim()) {
        result.push(
          <ReactMarkdown
            key={`text-${lastPosition}`}
            remarkPlugins={[remarkGfm, remarkMath]}
            rehypePlugins={[rehypeRaw, rehypeKatex]}
            components={markdownComponents(message.completed, message.content)}
          >
            {textSegment}
          </ReactMarkdown>
        );
      }
    }

    // 添加未包含在消息中的工具调用
    const includedTools = new Set(Object.keys(toolPositions).map(name => name.toLowerCase()));

    toolCalls.forEach(tool => {
      const toolName = tool.label.replace('CALL ', '').toLowerCase();
      if (!includedTools.has(toolName)) {
        // 这个工具调用没有明确标记，添加到末尾
        result.push(
          <ToolCallTag
            key={`tool-${tool.label}`}
            label={tool.label}
            status={tool.status}
            elapsedTime={tool.elapsedTime}
          />
        );
      }
    });

    return result;
  };

  // 预定义Markdown组件配置
  const markdownComponents = (messageCompleted?: boolean, originalContent?: string) => ({
    p: (props: any) => <p style={{ margin: '8px 0' }} {...props} />,
    h1: (props: any) => <h1 style={{ fontSize: '1.6em', margin: '16px 0 8px 0', borderBottom: '1px solid #eaecef', paddingBottom: '0.3em' }} {...props} />,
    h2: (props: any) => <h2 style={{ fontSize: '1.4em', margin: '14px 0 8px 0', borderBottom: '1px solid #eaecef', paddingBottom: '0.3em' }} {...props} />,
    h3: (props: any) => <h3 style={{ fontSize: '1.2em', margin: '12px 0 8px 0' }} {...props} />,
    ul: (props: any) => <ul style={{ margin: '8px 0', paddingLeft: '20px' }} {...props} />,
    ol: (props: any) => <ol style={{ margin: '8px 0', paddingLeft: '20px' }} {...props} />,
    li: (props: any) => <li style={{ margin: '4px 0' }} {...props} />,
    blockquote: (props: any) => <blockquote style={{ margin: '8px 0', padding: '0 16px', borderLeft: '4px solid #dfe2e5', color: '#6a737d' }} {...props} />,
    table: (props: any) => <table style={{ borderCollapse: 'collapse', margin: '12px 0', width: '100%' }} {...props} />,
    th: (props: any) => <th style={{ padding: '6px 13px', border: '1px solid #dfe2e5', backgroundColor: '#f6f8fa' }} {...props} />,
    td: (props: any) => <td style={{ padding: '6px 13px', border: '1px solid #dfe2e5' }} {...props} />,
    a: (props: any) => <a style={{ color: '#0366d6', textDecoration: 'none' }} target="_blank" rel="noopener noreferrer" {...props} />,
    img: (props: any) => {
      const handleImageClick = () => {
        openPreview([{ src: props.src, alt: props.alt || '' }]);
      };

      return (
        <div style={{ position: 'relative', display: 'inline-block', maxWidth: '500px', margin: '8px 0' }}>
          <img
            style={{
              maxWidth: '100%',
              maxHeight: '300px',
              height: 'auto',
              borderRadius: '4px',
              display: 'block',
              cursor: 'zoom-in',
              objectFit: 'contain',
            }}
            loading="lazy"
            referrerPolicy="no-referrer"
            onClick={handleImageClick}
            onError={(e) => {
              console.error('图片加载失败:', e);
              (e.target as HTMLImageElement).alt = '图片加载失败';
              (e.target as HTMLImageElement).style.border = '1px dashed #d9d9d9';
              (e.target as HTMLImageElement).style.padding = '8px';
              (e.target as HTMLImageElement).style.backgroundColor = '#f5f5f5';
            }}
            {...props}
          />
          <div
            style={{
              position: 'absolute',
              top: '8px',
              right: '8px',
              backgroundColor: 'rgba(0,0,0,0.5)',
              borderRadius: '4px',
              padding: '4px',
              cursor: 'pointer',
              color: 'white',
              fontSize: '14px'
            }}
            onClick={handleImageClick}
          >
            <ZoomInOutlined />
          </div>
        </div>
      );
    },
    code: ({ inline, className, children, ...props }: any) => {
      const match = /language-(\w+)/.exec(className || '');
      const lang = match && match[1] ? match[1] : '';

      if (inline) {
        return (
          <code
            style={{
              backgroundColor: '#f6f8fa',
              padding: '2px 4px',
              borderRadius: '3px',
              fontSize: '0.9em',
              fontFamily: 'SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace'
            }}
            {...props}
          >
            {children}
          </code>
        );
      }

      if (!lang) {
        return (
          <span style={{
            display: 'inline',
            padding: '2px 4px',
            backgroundColor: '#f5f5f5',
            borderRadius: '4px',
            fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif',
          }}>
            {children}
          </span>
        );
      }

      return <CodeBlockWithCopy language={lang} messageCompleted={messageCompleted} originalMessage={originalContent}>{children}</CodeBlockWithCopy>;
    }
  });

  return (
    <div className="markdown-content" style={{
      fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif',
      fontSize: '14px',
      maxWidth: '100%',
      overflowWrap: 'break-word',
      wordBreak: 'break-word'
    }}>
      {renderContentWithTools()}
    </div>
  );
};

const AiChat: React.FC<AiChatProps> = ({ visible, onClose, problemDescription, studentCode, programmingLanguage, errorMessage, output, tags }) => {
  const [messages, setMessages] = useState<Message[]>([]);
  const [inputValue, setInputValue] = useState('');
  const [loading, setLoading] = useState(false);
  const [taskId, setTaskId] = useState('');
  const [messageId, setMessageId] = useState('');
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const [currentResponse, setCurrentResponse] = useState('');
  const [conversationId, setConversationId] = useState(null);
  const [userId, setUserId] = useState<string>('user-' + Date.now());
  const [suggestedQuestions, setSuggestedQuestions] = useState<string[]>([]);
  const [isUploading, setIsUploading] = useState(false);
  const [uploadedFiles, setUploadedFiles] = useState<Array<{ id: string, name: string, url?: string, type?: string, local?: boolean }>>([]);
  const [pendingFiles, setPendingFiles] = useState<Array<{ id: string, name: string, url?: string, type?: string, local?: boolean }>>([]);
  const [mcpModalVisible, setMcpModalVisible] = useState(false);
  const [mcpActiveTab, setMcpActiveTab] = useState<'form' | 'json' | 'list'>('form');
  const [mcpName, setMcpName] = useState('');
  const [mcpUrl, setMcpUrl] = useState('');
  const [mcpJsonValue, setMcpJsonValue] = useState('');
  const [mcpServers, setMcpServers] = useState<Record<string, MCPServer>>({});

  const fileInputRef = useRef<HTMLInputElement>(null);
  const [showUrlInput, setShowUrlInput] = useState(false);
  const [urlValue, setUrlValue] = useState('');
  // 图片预览状态
  const { previewState, openPreview, closePreview } = useImagePreview();


  const chatContainerRef = useRef<HTMLDivElement>(null);
  const [shouldAutoScroll, setShouldAutoScroll] = useState(true);
  const userScrolledUp = useRef(false);
  const [expandedWorkflowMap, setExpandedWorkflowMap] = useState<{ [msgIndex: number]: boolean }>({});

  // 直接追加消息内容
  const appendMessageContent = useCallback((text: string) => {
    if (!text) return;

    setMessages(prev => {
      if (prev.length === 0) return prev;
      const lastMessage = prev[prev.length - 1];
      if (lastMessage.role === 'assistant') {
        // 检查是否需要在当前位置插入换行符以使工具调用显示更好
        const currentPosition = lastMessage.content.length;
        const toolPositions = lastMessage.toolPositions || {};
        let processedText = text;

        // 检查是否有工具刚好位于当前位置
        for (const position of Object.values(toolPositions)) {
          // 如果工具标记位置接近当前位置，需要考虑在文本前后添加换行符
          if (Math.abs(position - currentPosition) < 3) {
            // 确保工具前后有合适的空白
            if (!lastMessage.content.endsWith('\n\n') && !lastMessage.content.endsWith('\n')) {
              processedText = '\n\n' + processedText;
            }

            // 如果工具调用后面紧接着有文本，也需要添加空白
            if (!processedText.startsWith('\n') && !processedText.startsWith(' ')) {
              processedText = '\n\n' + processedText;
            }

            break;
          }
        }

        // 保留工具位置信息和其他属性，直接拼接内容
        return [
          ...prev.slice(0, -1),
          {
            ...lastMessage,
            content: lastMessage.content + processedText,
            // 确保保留其他所有原有属性
            tools: lastMessage.tools,
            workflow: lastMessage.workflow,
            toolPositions: lastMessage.toolPositions,
            completed: lastMessage.completed,
            files: lastMessage.files
          }
        ];
      }
      return prev;
    });

    // 自动滚动
    if (shouldAutoScroll && !userScrolledUp.current) {
      setTimeout(scrollToBottom, 10);
    }
  }, [shouldAutoScroll]);



  const scrollToBottom = useCallback(() => {
    if (!chatContainerRef.current) return;

    chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;
  }, []);

  const handleScroll = useCallback(() => {
    if (!chatContainerRef.current) return;

    const container = chatContainerRef.current;
    const { scrollTop, scrollHeight, clientHeight } = container;

    // 距离底部的距离
    const distanceFromBottom = scrollHeight - scrollTop - clientHeight;

    if (distanceFromBottom < 5) {
      if (!shouldAutoScroll) {
        setShouldAutoScroll(true);
        userScrolledUp.current = false;
      }
    }
    // 用户向上滚动超过100px，关闭自动滚动
    else if (distanceFromBottom > 100 && shouldAutoScroll) {
      setShouldAutoScroll(false);
      userScrolledUp.current = true;
    }
  }, [shouldAutoScroll]);

  useEffect(() => {
    if (shouldAutoScroll && chatContainerRef.current && !userScrolledUp.current) {
      scrollToBottom();
    }
  }, [messages, scrollToBottom, shouldAutoScroll]);

  useEffect(() => {
    if (visible) {
      // 默认启用自动滚动
      setShouldAutoScroll(true);
      userScrolledUp.current = false;

      // 延迟确保DOM已更新
      setTimeout(scrollToBottom, 100);
    }
  }, [visible, scrollToBottom]);

  // 使用全局triggerImagePreview函数处理图片预览
  useEffect(() => {
    // 设置全局triggerImagePreview函数
    window.triggerImagePreview = (src: string) => {
      openPreview([{ src }]);
    };

    return () => {
      // 清理函数
      delete window.triggerImagePreview;
    };
  }, [openPreview]);

  // 处理工具调用事件的函数
  const handleAgentLogEvent = (jsonData: any) => {
    if (jsonData.data && jsonData.data.label && jsonData.data.status) {
      const toolData = jsonData.data;

      // 只处理有CALL前缀的工具
      if (toolData.label.startsWith('CALL ')) {
        const toolCall: ToolCallProps = {
          label: toolData.label,
          status: toolData.status,
          icon: toolData.metadata?.icon,
          elapsedTime: toolData.metadata?.elapsed_time
        };

        // 记录工具调用到消息的tools数组，但不立即添加到内容中
        setMessages(prev => {
          const lastMessage = prev[prev.length - 1];
          if (!lastMessage) return prev;

          // 更新或添加工具调用到tools数组
          if (lastMessage.tools) {
            const existingToolIndex = lastMessage.tools.findIndex(
              tool => tool.label === toolCall.label
            );

            if (existingToolIndex >= 0) {
              // 更新现有工具
              const updatedTools = [...lastMessage.tools];
              updatedTools[existingToolIndex] = toolCall;

              return [
                ...prev.slice(0, -1),
                { ...lastMessage, tools: updatedTools }
              ];
            } else {
              // 添加新工具
              return [
                ...prev.slice(0, -1),
                { ...lastMessage, tools: [...lastMessage.tools, toolCall] }
              ];
            }
          } else {
            // 第一个工具调用
            return [
              ...prev.slice(0, -1),
              { ...lastMessage, tools: [toolCall] }
            ];
          }
        });

        // 如果是工具开始调用，标记需要在当前位置插入工具组件
        if (toolCall.status === 'start') {
          const toolName = toolCall.label.replace('CALL ', '');

          // 给当前消息添加一个特殊属性，表示在当前位置需要显示工具调用标签
          setMessages(prev => {
            const lastMessage = prev[prev.length - 1];
            if (!lastMessage) return prev;

            // 计算当前位置
            const currentPosition = lastMessage.content.length;

            // 现有的工具调用位置记录
            const toolPositions = lastMessage.toolPositions || {};

            // 添加新的工具调用位置
            return [
              ...prev.slice(0, -1),
              {
                ...lastMessage,
                toolPositions: {
                  ...toolPositions,
                  [toolName]: currentPosition
                }
              }
            ];
          });

          // 为下一次内容更新添加换行符
          appendMessageContent('\n\n');
        }

        // 滚动到底部
        if (shouldAutoScroll && !userScrolledUp.current) {
          setTimeout(scrollToBottom, 10);
        }
      }
    }
  };

  const processStreamMessage = (data: string) => {
    try {
      if (!data.startsWith('data: ')) {
        console.warn('收到非SSE格式数据:', data);
        return;
      }

      const jsonStr = data.replace('data: ', '');
      const jsonData = JSON.parse(jsonStr);

      // 首先检查是否是工具调用事件，需要优先处理
      if (jsonData.event === 'agent_log' && jsonData.data?.label?.startsWith('CALL ')) {
        // 处理工具调用事件
        handleAgentLogEvent(jsonData);
        return; // 优先处理工具事件后返回
      }

      switch (jsonData.event) {
        case 'workflow_started':
          console.log('工作流开始, ID:', jsonData.task_id);
          setTaskId(jsonData.task_id);
          setConversationId(jsonData.conversation_id);

          // 初始化工作流 - 只添加工作流ID，不预定义节点
          setMessages(prev => {
            const lastMessage = prev[prev.length - 1];
            if (lastMessage && lastMessage.role === 'assistant') {
              return [
                ...prev.slice(0, -1),
                {
                  ...lastMessage,
                  workflow: {
                    taskId: jsonData.task_id,
                    nodes: [] // 不预定义节点，只在收到node事件时添加
                  }
                }
              ];
            }
            return prev;
          });
          break;

        case 'node_started':
          console.log('节点开始执行:', jsonData.data?.title);
          // 更新工作流节点状态
          setMessages(prev => {
            const lastMessage = prev[prev.length - 1];
            if (lastMessage && lastMessage.workflow) {
              const nodeId = jsonData.data?.node_id;
              const title = jsonData.data?.title;
              const index = jsonData.data?.index; // 获取节点顺序

              // 查找或添加节点
              let nodeFound = false;
              const updatedNodes = lastMessage.workflow.nodes.map(node => {
                if ((node.id === nodeId)) {
                  nodeFound = true;
                  return {
                    ...node,
                    status: 'running',
                    startTime: Date.now(),
                    index: index !== undefined ? index : node.index,
                    title: title || node.title // 使用新的标题或保留现有标题
                  };
                }
                return node;
              });

              // 如果没找到节点，添加新节点
              if (!nodeFound && nodeId && title) {
                updatedNodes.push({
                  id: nodeId,
                  title: title,
                  status: 'running',
                  startTime: Date.now(),
                  index: index // 保存执行顺序
                });

                // 确保节点按执行顺序排序
                updatedNodes.sort((a, b) => {
                  if (a.index !== undefined && b.index !== undefined) {
                    return a.index - b.index;
                  } else if (a.index !== undefined) {
                    return -1;
                  } else if (b.index !== undefined) {
                    return 1;
                  }
                  return 0;
                });
              }

              // 立即更新状态
              return [
                ...prev.slice(0, -1),
                {
                  ...lastMessage,
                  workflow: {
                    ...lastMessage.workflow,
                    nodes: updatedNodes
                  }
                }
              ];
            }
            return prev;
          });
          break;

        case 'node_finished':
          console.log('节点执行完成:', jsonData.data?.node_id);
          // 更新工作流节点状态
          setMessages(prev => {
            const lastMessage = prev[prev.length - 1];
            if (lastMessage && lastMessage.workflow) {
              const nodeId = jsonData.data?.node_id;
              const status = jsonData.data?.status || 'succeeded';
              const elapsedTime = jsonData.data?.elapsed_time;
              const index = jsonData.data?.index; // 获取节点顺序
              const title = jsonData.data?.title; // 获取节点标题

              // 计算节点执行时间
              const calculatedTime = (node: WorkflowNode) => {
                if (elapsedTime !== undefined) {
                  return typeof elapsedTime === 'number' ?
                    `${elapsedTime.toFixed(3)} s` :
                    String(elapsedTime);
                } else if (node.startTime) {
                  return `${((Date.now() - node.startTime) / 1000).toFixed(3)} s`;
                }
                return undefined;
              };

              let nodeFound = false;
              const updatedNodes = lastMessage.workflow.nodes.map(node => {
                if (node.id === nodeId) {
                  nodeFound = true;
                  return {
                    ...node,
                    status: status as 'succeeded' | 'failed' | 'stopped',
                    elapsedTime: calculatedTime(node),
                    index: index !== undefined ? index : node.index,
                    title: title || node.title
                  };
                }
                return node;
              });

              // 如果没找到节点，添加新节点
              if (!nodeFound && nodeId) {
                updatedNodes.push({
                  id: nodeId,
                  title: title || `节点 ${nodeId}`,
                  status: status as 'succeeded' | 'failed' | 'stopped',
                  elapsedTime: elapsedTime !== undefined ?
                    (typeof elapsedTime === 'number' ? `${elapsedTime.toFixed(3)} s` : String(elapsedTime)) :
                    undefined,
                  index: index
                });

                // 确保节点按执行顺序排序
                updatedNodes.sort((a, b) => {
                  if (a.index !== undefined && b.index !== undefined) {
                    return a.index - b.index;
                  } else if (a.index !== undefined) {
                    return -1;
                  } else if (b.index !== undefined) {
                    return 1;
                  }
                  return 0;
                });
              }

              // 如果节点状态为失败或停止，标记消息为已完成，移除加载占位符
              const messageCompleted = status === 'failed' || status === 'stopped' ? true : lastMessage.completed;

              // 立即更新UI以显示节点状态和时间
              return [
                ...prev.slice(0, -1),
                {
                  ...lastMessage,
                  workflow: {
                    ...lastMessage.workflow,
                    nodes: updatedNodes
                  },
                  completed: messageCompleted
                }
              ];
            }
            return prev;
          });

          // 如果节点状态为失败或停止，停止加载状态
          if (jsonData.data?.status === 'failed' || jsonData.data?.status === 'stopped') {
            setLoading(false);
          }
          break;

        case 'message':
          if (jsonData.answer) {
            // 直接将新文本附加到当前消息中
            appendMessageContent(jsonData.answer);
          } else {
            console.warn('收到message事件但没有answer字段');
          }
          break;

        case 'workflow_finished':
          console.log('工作流完成');
          // 工作流完成时不自动标记节点为成功
          // 只标记整个消息为完成
          setMessages(prev => {
            const lastMessage = prev[prev.length - 1];
            if (lastMessage && lastMessage.workflow) {
              return [
                ...prev.slice(0, -1),
                {
                  ...lastMessage,
                  // 不修改节点状态，保持原样
                  workflow: {
                    ...lastMessage.workflow
                  }
                }
              ];
            }
            return prev;
          });
          break;

        case 'message_end':
          console.log('消息结束');
          if (jsonData.message_id) {
            setMessageId(jsonData.message_id);
            // 获取建议问题
            fetchSuggestedQuestions(jsonData.message_id);
          }

          // 直接标记消息为已完成
          setMessages(prev => {
            if (prev.length === 0) return prev;
            const lastMessage = prev[prev.length - 1];

            // 消息完成时，若启用自动滚动，则滚动到底部
            if (shouldAutoScroll && !userScrolledUp.current) {
              setTimeout(scrollToBottom, 100);
            }

            return [
              ...prev.slice(0, -1),
              {
                ...lastMessage,
                content: lastMessage.content,
                completed: true
              }
            ];
          });
          setLoading(false);
          break;

        case 'agent_log':
          // 工具调用现在由handleAgentLogEvent处理
          break;

        case 'error':
          console.error('收到错误事件:', jsonData);
          // 提取错误信息
          const errorMessage = jsonData.message || '发生未知错误';
          const errorCode = jsonData.code || '';

          // 直接更新最后一条消息，添加错误信息
          setMessages(prev => {
            if (prev.length === 0) return prev;
            const lastMessage = prev[prev.length - 1];

            // 构建红色错误信息
            const errorContent = lastMessage.content +
              `\n\n<div style="color: #f5222d; padding: 10px; background-color: #fff1f0; border-radius: 4px; border: 1px solid #ffccc7;">` +
              `<strong>错误 ${errorCode ? `(${errorCode})` : ''}:</strong> ${errorMessage}` +
              `</div>`;

            return [
              ...prev.slice(0, -1),
              {
                ...lastMessage,
                content: errorContent,
                completed: true // 标记为已完成，移除加载占位符
              }
            ];
          });

          // 停止加载状态
          setLoading(false);
          break;

        default:
          console.log('未处理的事件类型:', jsonData.event);
          break;
      }

    } catch (error) {
      console.error('处理消息流时出错:', error, '原始数据:', data);
    }
  };

  const handleSend = async () => {
    if (!inputValue.trim() && pendingFiles.length === 0) return;

    const userMessage = inputValue;
    setInputValue('');

    // 清空建议问题
    setSuggestedQuestions([]);

    // 重置自动滚动状态
    setShouldAutoScroll(true);
    userScrolledUp.current = false;
    setTimeout(scrollToBottom, 50);

    try {
      // 处理带有文件的消息
      if (pendingFiles.length > 0) {
        setUploadedFiles(prev => [...prev, ...pendingFiles]);

        // 处理文件消息
        let fileMessage = userMessage.trim();
        if (!fileMessage) {
          // 如果用户没有输入消息，生成一个适当的默认消息
          const imageFiles = pendingFiles.filter(file => file.type?.startsWith('image/'));
          if (imageFiles.length > 0) {
            fileMessage = imageFiles.length === 1
              ? `分享了一张图片`
              : `分享了 ${imageFiles.length} 张图片`;
          } else {
            fileMessage = pendingFiles.length === 1
              ? `分享了文件: ${pendingFiles[0].name}`
              : `分享了 ${pendingFiles.length} 个文件`;
          }
        }

        // 获取待发送文件ID
        const fileIds = pendingFiles.map(file => file.id);


        setPendingFiles([]);

        // 发送消息和文件ID
        await handleSendPrompt(fileMessage, true, fileIds);
      } else {
        // 普通消息发送
        await handleSendPrompt(userMessage, true);
      }
    } catch (error) {
      console.error('发送消息时出错:', error);
      message.error('消息发送失败');
    }
  };

  const handleFileUpload = async () => {
    if (fileInputRef.current) {
      fileInputRef.current.click();
    }
  };

  // 将文件转换为base64数据URL
  const fileToDataUrl = (file: File): Promise<string> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result as string);
      reader.onerror = reject;
      reader.readAsDataURL(file);
    });
  };

  const uploadFile = async (file: File) => {
    if (!file) return;

    setIsUploading(true);
    const formData = new FormData();
    formData.append('file', file);
    formData.append('user', userId);

    try {
      const response = await fetch(`${API_URL}/files/upload`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${API_KEY}`
        },
        body: formData
      });

      if (response.ok) {
        const result = await response.json();
        const fileType = file.type || '';
        const isImage = fileType.startsWith('image/');

        // 对于图片文件，转换为持久的data URL而不是临时的blob URL
        let fileUrl = '';
        if (isImage) {
          try {
            fileUrl = await fileToDataUrl(file);
          } catch (err) {
            console.error('转换图片到data URL失败:', err);
            // 如果转换失败，回退到blob URL
            fileUrl = URL.createObjectURL(file);
          }
        }

        // 添加到待发送文件，而不是直接发送
        setPendingFiles(prev => [
          ...prev,
          {
            id: result.id,
            name: result.name,
            type: fileType,
            url: fileUrl,
            local: true
          }
        ]);

        message.success(`文件 ${result.name} 上传成功，等待发送`);
      } else {
        message.error('文件上传失败');
        console.error('文件上传失败:', await response.text());
      }
    } catch (error) {
      message.error('文件上传失败');
      console.error('文件上传错误:', error);
    } finally {
      setIsUploading(false);
    }
  };

  const uploadFromUrl = async (url: string) => {
    if (!url.trim()) return;

    setIsUploading(true);
    const fileName = url.split('/').pop() || 'file_from_url';
    const fileId = 'url_' + Date.now();
    const isImage = /\.(jpg|jpeg|png|gif|webp)$/i.test(url);

    try {
      // 检查URL是否可访问（特别是图片）
      if (isImage) {
        const checkImage = new Image();
        checkImage.onload = () => {
          // 图片加载成功，添加到待发送文件
          setPendingFiles(prev => [
            ...prev,
            {
              id: fileId,
              name: fileName,
              type: 'image/unknown',
              url: url, // 保留原始URL
              local: false
            }
          ]);
          message.success(`图片URL添加成功，等待发送`);

          // 立即清除URL输入
          setUrlValue('');
          setShowUrlInput(false);
          setIsUploading(false);
        };

        checkImage.onerror = () => {
          message.error('图片URL无法访问');
          setIsUploading(false);
        };

        checkImage.src = url;
      } else {
        // 非图片类型，直接添加
        setPendingFiles(prev => [
          ...prev,
          {
            id: fileId,
            name: fileName,
            type: 'image/unknown',
            url: url, // 保留原始URL
            local: false
          }
        ]);

        message.success(`URL添加成功，等待发送`);

        // 立即清除URL输入
        setUrlValue('');
        setShowUrlInput(false);
        setIsUploading(false);
      }
    } catch (error) {
      message.error('URL添加失败');
      console.error('URL添加错误:', error);
      setIsUploading(false);
    }
  };

  const removePendingFile = (fileId: string) => {
    setPendingFiles(files => files.filter(file => file.id !== fileId));
  };

  const handleSendPrompt = async (prompt: string, show: boolean, fileIds?: string[]) => {
    // 准备需要发送的文件信息
    const pendingFilesToSend = fileIds && fileIds.length > 0
      ? pendingFiles.filter(file => fileIds.includes(file.id))
      : [];

    if (show) {
      // 准备显示的消息内容，包括图片
      let contentWithImages = prompt;

      // 如果有图片类型的文件，添加到消息内容中
      const imageFiles = pendingFilesToSend.filter(file => file.type?.startsWith('image/'));
      if (imageFiles.length > 0) {
        // 为简化处理，只将图片URL添加到消息末尾
        imageFiles.forEach(file => {
          if (file.url) {
            // 使用img标签代替Markdown语法，确保与输入框预览一致
            // 将图片包裹在div中，确保每张图片单独成行并有适当边距
            contentWithImages += `\n<div style="margin: 10px 0;">
              <img src="${file.url}" alt="${file.name}" style="max-width: 80%; max-height: 250px; object-fit: cover; border-radius: 8px; border: 1px solid #eaeaea; display: block;">
            </div>`;
          }
        });
      }

      setMessages(prev => {
        const newMessages = [...prev, {
          role: 'user' as const,
          content: contentWithImages,
          files: pendingFilesToSend
        }];
        return newMessages;
      });
    }

    setMessages(prev => {
      const newMessages = [...prev, { role: 'assistant' as const, content: '' }];
      return newMessages;
    });

    setTimeout(scrollToBottom, 50);

    setLoading(true);
    setCurrentResponse('');

    try {
      console.log('发送请求至:', API_URL);

      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 30000);

      // 准备API需要的文件格式
      const files = [];

      // 如果有指定的文件ID
      if (fileIds && fileIds.length > 0) {
        // 查找这些文件的信息
        for (const fileId of fileIds) {
          const file = pendingFiles.find(f => f.id === fileId);
          if (file) {
            // 确定文件类型
            let fileType = 'document';
            if (file.type?.startsWith('image/')) fileType = 'image';
            else if (file.type?.startsWith('audio/')) fileType = 'audio';
            else if (file.type?.startsWith('video/')) fileType = 'video';

            // 确定传输方式
            if (file.url && !file.local) {
              // 远程URL
              files.push({
                type: fileType,
                transfer_method: 'remote_url',
                url: file.url
              });
            } else if (file.id) {
              // 本地上传的文件
              files.push({
                type: fileType,
                transfer_method: 'local_file',
                upload_file_id: file.id
              });
            }
          }
        }
      }

      // 添加MCP servers配置 - 转换为字符串形式的JSON，去掉最外层大括号
      let mcpServersConfig = {};
      if (Object.keys(mcpServers).length > 0) {
        // 创建手动转义的字符串
        let escapedString = '';

        // 遍历所有服务器配置，手动构建带转义的字符串
        Object.entries(mcpServers).forEach(([key, server], index) => {
          // 转义key
          const escapedKey = `\\"${key}\\"`;

          // 转义服务器配置中的值
          const escapedType = `\\"${server.type}\\"`;
          const escapedUrl = `\\"${server.url}\\"`;

          // 构建单个服务器的配置字符串
          const serverConfigString = `${escapedKey}:{\\"type\\":${escapedType},\\"url\\":${escapedUrl}}`;

          // 添加到结果字符串，最后一项不添加逗号
          if (index < Object.keys(mcpServers).length - 1) {
            escapedString += serverConfigString + ',';
          } else {
            escapedString += serverConfigString;
          }
        });

        mcpServersConfig = { mcpServers: escapedString };
      }

      const response = await fetch(`${API_URL}/chat-messages`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          inputs: {
            problem_description: problemDescription,
            student_code: studentCode,
            language: programmingLanguage,
            error_message: errorMessage,
            output: output,
            ...(tags && { tags: tags.includes('，') ? tags.replace(/，/g, ',') : tags }),
            ...mcpServersConfig // 添加MCP服务器配置
          },
          query: prompt,
          response_mode: 'streaming',
          conversation_id: conversationId,
          user: userId,
          // 添加文件信息
          ...(files.length > 0 && { files })
        }),
        signal: controller.signal
      });

      clearTimeout(timeoutId);

      if (!response.ok) {
        const errorText = await response.text();
        console.error('API响应错误:', response.status, errorText);
        throw new Error(`API 请求失败: ${response.status} ${errorText}`);
      }

      const reader = response.body?.getReader();
      const decoder = new TextDecoder();

      if (!reader) {
        throw new Error('无法读取响应流');
      }

      let buffer = '';
      let hasReceivedData = false;

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        const chunk = decoder.decode(value);
        if (chunk && !hasReceivedData) {
          hasReceivedData = true;
          console.log('收到首个数据块');
        }

        buffer += chunk;
        const lines = buffer.split('\n');

        for (let i = 0; i < lines.length - 1; i++) {
          const line = lines[i].trim();
          if (line) {
            console.log('处理消息行:', line.substring(0, 50) + (line.length > 50 ? '...' : ''));
            processStreamMessage(line);
          }
        }

        buffer = lines[lines.length - 1];
      }

      if (buffer.trim()) {
        processStreamMessage(buffer.trim());
      }

      if (!hasReceivedData) {
        console.warn('未收到任何数据');
        message.warning('服务器未返回任何数据');
      }
    } catch (error: any) {
      if (error.name === 'AbortError') {
        message.error('请求超时，请检查网络连接或稍后重试');
        console.error('请求超时');
      } else {
        message.error('发送消息失败，请稍后重试');
        console.error('发送消息失败:', error);
      }
      setLoading(false);
    }
  };

  const handleStop = async () => {
    if (!taskId) {
      console.error('没有正在进行的任务');
      message.error('没有正在进行的任务');
      return;
    }

    try {
      const response = await fetch(`${API_URL}/chat-messages/${taskId}/stop`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${API_KEY}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ user: userId })
      });

      if (response.ok) {
        message.success('已停止响应');
        setLoading(false);
        setTaskId('');
        setSuggestedQuestions([]); // 清空建议问题

        // 直接标记为完成
        setMessages(prev => {
          const lastMessage = prev[prev.length - 1];
          if (lastMessage && lastMessage.role === 'assistant') {
            return [
              ...prev.slice(0, -1),
              {
                ...lastMessage,
                completed: true
              }
            ];
          }
          return prev;
        });

        // 将正在运行的工作流节点标记为stopped状态
        setMessages(prev => {
          const lastMessage = prev[prev.length - 1];
          if (lastMessage && lastMessage.workflow) {
            // 找到所有正在运行的节点，将其状态改为stopped
            const updatedNodes = lastMessage.workflow.nodes.map(node => {
              if (node.status === 'running' || node.status === 'waiting') {
                // 计算已运行时间
                let elapsedTime = node.elapsedTime;
                if (!elapsedTime && node.startTime) {
                  elapsedTime = `${((Date.now() - node.startTime) / 1000).toFixed(3)} s`;
                }

                return {
                  ...node,
                  status: 'stopped',
                  elapsedTime: elapsedTime
                };
              }
              return node;
            });

            return [
              ...prev.slice(0, -1),
              {
                ...lastMessage,
                workflow: {
                  ...lastMessage.workflow,
                  nodes: updatedNodes
                },
                completed: true // 标记消息为已完成
              }
            ];
          }

          // 如果没有工作流，只标记消息为已完成
          if (lastMessage && lastMessage.role === 'assistant') {
            return [
              ...prev.slice(0, -1),
              {
                ...lastMessage,
                completed: true
              }
            ];
          }

          return prev;
        });
      }
    } catch (error) {
      console.error('停止请求失败:', error);
    }
  };

  const handleKeyPress = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      if (loading) {
        handleStop();
      } else {
        handleSend();
      }
    }
  };

  

  const fetchSuggestedQuestions = async (msgId: string) => {
    try {
      const response = await fetch(`${API_URL}/messages/${msgId}/suggested?user=${userId}`, {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${API_KEY}`,
          'Content-Type': 'application/json'
        }
      });

      if (response.ok) {
        const data = await response.json();
        if (data.result === 'success' && data.data && Array.isArray(data.data)) {
          setSuggestedQuestions(data.data);
        } else {
          console.error('获取建议问题格式错误:', data);
          setSuggestedQuestions([]);
        }
      } else {
        console.error('获取建议问题失败:', response.status);
        setSuggestedQuestions([]);
      }
    } catch (error) {
      console.error('获取建议问题出错:', error);
      setSuggestedQuestions([]);
    }
  };

  const handleSuggestedQuestionClick = (question: string) => {
    // 直接发送问题，不经过输入框
    setSuggestedQuestions([]); // 清空建议问题

    // 重置自动滚动状态
    setShouldAutoScroll(true);
    userScrolledUp.current = false;
    setTimeout(scrollToBottom, 50);

    // 添加用户消息并发送
    setMessages(prev => {
      const newMessages = [...prev, { role: 'user' as const, content: question }];
      return newMessages;
    });

    handleSendPrompt(question, false);
  };

  const handleClearChat = () => {
    // 如果有正在进行的任务，先停止任务
    if (loading && taskId) {
      handleStop();
    }

    // 延迟清空对话，确保停止任务完成
    setTimeout(() => {
      setMessages([]);
      setConversationId(null);
      setUserId('user-' + Date.now());
      setSuggestedQuestions([]);
      setUploadedFiles([]);
      setPendingFiles([]);
      setShowUrlInput(false);
      setUrlValue('');
      setLoading(false); // 确保loading状态被重置
      setTaskId(''); // 清空任务ID

      // 无需清理打字机状态，因为已经不再使用

      // 清空mermaid展开状态缓存
      mermaidExpandedStateCache.clear();
    }, loading ? 300 : 0); // 如果正在加载则延迟300ms，否则立即执行
  };

  // MCP服务器相关处理函数
  const handleMcpModalOpen = () => {
    setMcpModalVisible(true);
  };

  const handleMcpModalClose = () => {
    setMcpModalVisible(false);
    // 清空表单
    setMcpName('');
    setMcpUrl('');
    setMcpJsonValue('');
  };

  const handleMcpTabChange = (key: string) => {
    setMcpActiveTab(key as 'form' | 'json' | 'list');
  };

  const handleAddMcpByForm = () => {
    if (!mcpName.trim() || !mcpUrl.trim()) {
      message.error('请填写完整的MCP服务器信息');
      return;
    }

    // 添加到服务器列表
    setMcpServers(prev => ({
      ...prev,
      [mcpName]: {
        name: mcpName,
        url: mcpUrl,
        type: 'sse'
      }
    }));

    message.success(`MCP服务器 "${mcpName}" 已添加`);
    // 清空表单但不关闭对话框，切换到列表页
    setMcpName('');
    setMcpUrl('');
    setMcpActiveTab('list');
  };

  const handleAddMcpByJson = () => {
    try {
      // 解析JSON
      const jsonData = JSON.parse(mcpJsonValue);

      // 检查JSON格式是否正确 - 现在接受直接的MCP服务器配置，不需要mcpServers包装
      let mcpData = jsonData;
      if (jsonData.mcpServers) {
        // 如果包含在mcpServers中，则提取
        mcpData = jsonData.mcpServers;
      }

      // 检查格式是否正确
      if (typeof mcpData !== 'object' || mcpData === null) {
        message.error('JSON格式不正确，请提供有效的MCP服务器配置');
        return;
      }

      // 合并到现有服务器列表
      setMcpServers(prev => ({
        ...prev,
        ...mcpData
      }));

      message.success(`MCP服务器配置已添加`);
      // 清空表单但不关闭对话框，切换到列表页
      setMcpJsonValue('');
      setMcpActiveTab('list');
    } catch (error) {
      console.error('JSON解析错误:', error);
      message.error('JSON格式不正确，请检查');
    }
  };

  // 删除MCP服务器
  const handleDeleteMcp = (serverName: string) => {
    Modal.confirm({
      title: '确认删除',
      content: `确定要删除服务器 "${serverName}" 吗？`,
      okText: '确定',
      cancelText: '取消',
      onOk: () => {
        setMcpServers(prev => {
          const newServers = { ...prev };
          delete newServers[serverName];
          return newServers;
        });
        message.success(`服务器 "${serverName}" 已删除`);
      }
    });
  };

  // 启用/禁用MCP服务器
  const toggleServerDisabled = (serverName: string, disabled: boolean) => {
    setMcpServers(prev => ({
      ...prev,
      [serverName]: {
        ...prev[serverName],
        disabled: disabled,
        status: disabled ? 'disconnected' : 'connected'
      }
    }));

    message.success(`服务器 "${serverName}" 已${disabled ? '禁用' : '启用'}`);
  };

 
  return (
    <div style={{
      display: 'flex',
      flexDirection: 'column',
      height: '100%',
      width: '100%',
      overflow: 'hidden',
      backgroundColor: '#fff'
    }}>
      {/* 标题栏 */}
      <div style={{
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
        padding: '12px 16px',
        borderBottom: '1px solid #f0f0f0',
        backgroundColor: '#fafafa'
      }}>
        <span style={{ fontWeight: 500 }}>AI 助手</span>
        <Space>
          <Button
            type="text"
            size="small"
            icon={<SettingOutlined />}
            onClick={handleMcpModalOpen}
            style={{ padding: '4px' }}
            title="MCP设置"
          />
          <Button
            type="text"
            size="small"
            icon={<ReloadOutlined />}
            onClick={handleClearChat}
            style={{ padding: '4px' }}
            title="清空对话"
          />
          <Dropdown
            menu={{
              items: aiButtons.map(button => ({
                key: button.key,
                label: (
                  <span>
                    {button.icon}
                    <span style={{ marginLeft: '8px' }}>{button.text}</span>
                  </span>
                ),
                onClick: () => {
                  const prompt = button.prompt({
                    visible,
                    onClose,
                    problemDescription,
                    studentCode,
                    programmingLanguage,
                    errorMessage,
                    output,
                    tags
                  });
                  if (prompt) {
                    // 检查是否有正在进行的消息
                    const hasOngoingMessage = loading || (messages.length > 0 && !messages[messages.length - 1].completed);
                    
                    if (hasOngoingMessage) {
                      // 如果有正在进行的消息，放入输入框
                      setInputValue(prompt);
                    } else {
                      // 如果没有正在进行的消息，直接发送
                      setSuggestedQuestions([]); // 清空建议问题
                      setShouldAutoScroll(true);
                      userScrolledUp.current = false;
                      setTimeout(scrollToBottom, 50);
                      
                      // 添加用户消息并发送
                      setMessages(prev => {
                        const newMessages = [...prev, { role: 'user' as const, content: prompt }];
                        return newMessages;
                      });
                      
                      handleSendPrompt(prompt, false);
                    }
                  }
                }
              }))
            }}
            trigger={['click']}
            placement="bottomRight"
          >
            <Button
              type="text"
              size="small"
              icon={<MoreOutlined />}
              style={{ padding: '4px' }}
              title="更多功能"
            />
          </Dropdown>
        </Space>
      </div>
      <div style={{
        display: 'flex',
        flexDirection: 'column',
        height: '100%',
        width: '100%',
        overflow: 'hidden',
        backgroundColor: '#fff'
      }}>
        <style>
          {`
                .chat-messages::-webkit-scrollbar {
                  display: none;
                }
              `}
        </style>
        <div
          className="chat-messages"
          ref={chatContainerRef}
          onScroll={handleScroll}
          style={{
            overflowY: 'auto',
            overflowX: 'hidden',
            flex: 1,
            padding: '0 16px 16px',
            scrollbarWidth: 'none',
            msOverflowStyle: 'none',
          }}
        >
          <List
            dataSource={[...messages, ...(currentResponse ? [{ role: 'assistant' as const, content: currentResponse }] : [])]}
            renderItem={(message, idx) => (
              <List.Item style={{
                flexDirection: 'column',
                alignItems: message.role === 'user' ? 'flex-end' : 'flex-start',
                border: 'none',
                padding: '8px 0'
              }}>
                <div style={{
                  display: 'flex',
                  alignItems: 'flex-start',
                  maxWidth: '85%',
                  width: 'auto'
                }}>
                  <div style={{
                    display: 'flex',
                    alignItems: 'flex-start',
                    flexDirection: message.role === 'user' ? 'row-reverse' : 'row',
                    width: '100%'
                  }}>
                    <Avatar
                      icon={message.role === 'user' ? <UserOutlined /> : <RobotOutlined />}
                      style={{
                        backgroundColor: message.role === 'user' ? '#1890ff' : '#52c41a',
                        flexShrink: 0,
                        margin: message.role === 'user' ? '0 0 0 8px' : '0 8px 0 0'
                      }}
                    />
                    <div style={{
                      padding: '8px 12px',
                      backgroundColor: message.role === 'user' ? '#1890ff' : '#f0f2f5',
                      color: message.role === 'user' ? '#fff' : 'rgba(0, 0, 0, 0.85)',
                      borderRadius: '12px',
                      wordBreak: 'break-word',
                      maxWidth: '100%',
                      overflowWrap: 'break-word',
                      overflowX: 'hidden' // 防止水平滚动条
                    }}>
                      {message.workflow && message.role === 'assistant' && (
                        <WorkflowProcess
                          nodes={message.workflow.nodes}
                          completed={message.completed}
                          expanded={!!expandedWorkflowMap[idx]}
                          onToggle={() => setExpandedWorkflowMap(m => ({ ...m, [idx]: !m[idx] }))}
                        />
                      )}

                      <MemoizedMessageContent
                        message={message}
                        openPreview={openPreview}
                        isLatestAiMessage={message.role === 'assistant' && idx === messages.length - 1}
                      />
                    </div>
                  </div>
                </div>
              </List.Item>
            )}
          />
          <div ref={messagesEndRef} />
        </div>

        {/* 建议问题列表 - 只有当最后一条消息是已完成的助手消息时才显示 */}
        {suggestedQuestions.length > 0 && messages.length > 0 &&
          messages[messages.length - 1].role === 'assistant' &&
          messages[messages.length - 1].completed && (
            <div style={{
              padding: '8px 16px',
              borderTop: '1px solid #f0f0f0'
            }}>
              <Typography.Text type="secondary" style={{ fontSize: '12px', display: 'block', marginBottom: '8px' }}>
                猜你想问:
              </Typography.Text>
              <div style={{
                display: 'grid',
                gridTemplateColumns: 'repeat(3, 1fr)',
                gap: '8px'
              }}>
                {suggestedQuestions.map((question, index) => (
                  <Button
                    key={index}
                    size="small"
                    type="default"
                    style={{
                      borderRadius: '16px',
                      fontSize: '12px',
                      background: '#f0f2f5',
                      textAlign: 'center',
                      whiteSpace: 'normal',
                      height: 'auto',
                      padding: '4px 8px'
                    }}
                    onClick={() => handleSuggestedQuestionClick(question)}
                  >
                    {question}
                  </Button>
                ))}
              </div>
            </div>
          )}

        <div style={{
          padding: '16px',
          borderTop: '1px solid #f0f0f0',
          backgroundColor: '#fff'
        }}>
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            {/* 待发送文件预览区域 */}
            {pendingFiles.length > 0 && (
              <div style={{
                display: 'flex',
                flexWrap: 'wrap',
                gap: '8px',
                padding: '8px',
                backgroundColor: '#f9f9f9',
                borderRadius: '4px',
                marginBottom: '8px'
              }}>
                {pendingFiles.map(file => (
                  <div key={file.id} style={{
                    position: 'relative',
                    width: file.type?.startsWith('image/') ? '80px' : '120px',
                    height: file.type?.startsWith('image/') ? '80px' : 'auto',
                    border: '1px solid #e8e8e8',
                    borderRadius: '4px',
                    overflow: 'hidden',
                    padding: file.type?.startsWith('image/') ? 0 : '4px',
                    backgroundColor: 'white'
                  }}>
                    {/* 删除按钮 */}
                    <Button
                      type="text"
                      size="small"
                      icon={<CloseOutlined />}
                      style={{
                        position: 'absolute',
                        top: 0,
                        right: 0,
                        zIndex: 1,
                        backgroundColor: 'rgba(255, 255, 255, 0.8)',
                        padding: '2px',
                        margin: '2px',
                        borderRadius: '50%',
                        width: '16px',
                        height: '16px',
                        display: 'flex',
                        justifyContent: 'center',
                        alignItems: 'center',
                        border: 'none'
                      }}
                      onClick={() => removePendingFile(file.id)}
                    />

                    {file.type?.startsWith('image/') ? (
                      <div style={{ position: 'relative', width: '100%', height: '100%' }}>
                        <img
                          src={file.url}
                          alt={file.name}
                          style={{
                            width: '100%',
                            height: '100%',
                            objectFit: 'cover',
                            cursor: 'zoom-in',
                            borderRadius: '4px'
                          }}
                          onClick={() => openPreview([{ src: file.url || '', alt: file.name }])}
                        />
                        <div
                          style={{
                            position: 'absolute',
                            top: '4px',
                            right: '4px',
                            backgroundColor: 'rgba(0,0,0,0.5)',
                            borderRadius: '4px',
                            padding: '2px',
                            color: 'white',
                            fontSize: '12px',
                            cursor: 'pointer'
                          }}
                          onClick={() => openPreview([{ src: file.url || '', alt: file.name }])}
                        >
                          <ZoomInOutlined />
                        </div>
                      </div>
                    ) : (
                      <div style={{ fontSize: '12px', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
                        <PaperClipOutlined style={{ fontSize: '24px', margin: '4px 0' }} />
                        <div style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', width: '100%', textAlign: 'center' }}>
                          {file.name}
                        </div>
                      </div>
                    )}
                  </div>
                ))}
              </div>
            )}

            {/* URL输入弹窗 */}
            <Modal
              title="输入URL"
              open={showUrlInput}
              onOk={() => uploadFromUrl(urlValue)}
              onCancel={() => {
                setShowUrlInput(false);
                setUrlValue('');
              }}
              okText="确定"
              cancelText="取消"
              okButtonProps={{ disabled: !urlValue.trim() }}
            >
              <Input
                value={urlValue}
                onChange={(e) => setUrlValue(e.target.value)}
                placeholder="输入文件URL..."
                onPressEnter={() => urlValue.trim() && uploadFromUrl(urlValue)}
              />
            </Modal>

            {/* 输入和按钮区域 */}
            <div style={{ display: 'flex', marginBottom: '8px' }}>
              <input
                type="file"
                ref={fileInputRef}
                style={{ display: 'none' }}
                onChange={(e) => {
                  if (e.target.files && e.target.files[0]) {
                    uploadFile(e.target.files[0]);
                  }
                  // 重置文件输入，以便能够重复上传同一文件
                  e.target.value = '';
                }}
                accept="image/*,.pdf,.docx,.doc,.txt"
              />
              {isUploading ? (
                <div style={{ width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
                  <Spin size="small" style={{ marginRight: '8px' }} />
                  <span style={{ fontSize: '12px' }}>文件上传中...</span>
                </div>
              ) : (
                <div style={{ display: 'flex', width: '100%' }}>
                  <Input.TextArea
                    value={inputValue}
                    onChange={(e) => setInputValue(e.target.value)}
                    onKeyPress={handleKeyPress}
                    placeholder="输入消息..."
                    autoSize={{ minRows: 1, maxRows: 4 }}
                    style={{ marginRight: '8px', flex: 1 }}
                  />
                  <Popover
                    content={
                      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
                        <Button onClick={handleFileUpload}>本地上传</Button>
                        <Button onClick={() => setShowUrlInput(true)}>输入URL</Button>
                      </div>
                    }
                    trigger="click"
                    placement="top"
                  >
                    <Button
                      icon={<PaperClipOutlined />}
                      style={{ marginRight: '8px' }}
                      title="添加文件"
                    />
                  </Popover>
                  <Button
                    type="primary"
                    icon={loading && (!messages.length || !messages[messages.length - 1].completed) ? <StopOutlined /> : <SendOutlined />}
                    onClick={loading && (!messages.length || !messages[messages.length - 1].completed) ? handleStop : handleSend}
                  />
                </div>
              )}
            </div>
          </div>
        </div>
      </div>

      {/* MCP服务器配置对话框 */}
      <Modal
        title="添加 MCP Server"
        open={mcpModalVisible}
        onCancel={handleMcpModalClose}
        footer={null}
      >
        <style>
          {`
            .mcp-server-item .ant-collapse-header {
              padding: 6px 12px !important;
            }
            .mcp-server-item .ant-collapse-content-box {
              padding: 2px !important;
            }
          `}
        </style>
        <Tabs activeKey={mcpActiveTab} onChange={handleMcpTabChange}>
          <Tabs.TabPane tab="表单添加" key="form">
            <div style={{ marginTop: 16 }}>
              <div style={{ marginBottom: 16 }}>
                <span style={{ color: '#f5222d', marginRight: 4 }}>*</span>
                <span>名称</span>
                <Input
                  placeholder="MCP Server 名称，如 fetch、time 等"
                  value={mcpName}
                  onChange={e => setMcpName(e.target.value)}
                  style={{ marginTop: 8 }}
                />
              </div>
              <div style={{ marginBottom: 16 }}>
                <span style={{ color: '#f5222d', marginRight: 4 }}>*</span>
                <span>SSE 链接</span>
                <Input
                  placeholder="MCP Server SSE 链接"
                  value={mcpUrl}
                  onChange={e => setMcpUrl(e.target.value)}
                  style={{ marginTop: 8 }}
                />
              </div>
              <div style={{ textAlign: 'right', marginTop: 24 }}>
                <Button onClick={handleMcpModalClose} style={{ marginRight: 8 }}>
                  取消
                </Button>
                <Button type="primary" onClick={handleAddMcpByForm}>
                  确定
                </Button>
              </div>
            </div>
          </Tabs.TabPane>
          <Tabs.TabPane tab="JSON 添加" key="json">
            <div style={{ marginTop: 16 }}>
              <div style={{ marginBottom: 16 }}>
                <span style={{ color: '#f5222d', marginRight: 4 }}>*</span>
                <span>JSON</span>
                <Input.TextArea
                  placeholder={`{\n  "leetcode-mcp-server": {\n    "type": "sse",\n    "url": "https://mcp.api-inference.modelscope.cn/sse/xxx"\n  },\n  "howtocook-mcp": {\n    "type": "sse",\n    "url": "https://mcp.api-inference.modelscope.cn/sse/xxx"\n  }\n}`}
                  value={mcpJsonValue}
                  onChange={e => setMcpJsonValue(e.target.value)}
                  style={{ marginTop: 8, height: 200 }}
                />
              </div>
              <div style={{ textAlign: 'right', marginTop: 24 }}>
                <Button onClick={handleMcpModalClose} style={{ marginRight: 8 }}>
                  取消
                </Button>
                <Button type="primary" onClick={handleAddMcpByJson}>
                  确定
                </Button>
              </div>
            </div>
          </Tabs.TabPane>
          <Tabs.TabPane tab="已配置服务器" key="list">
            <div style={{ marginTop: 16 }}>
              {Object.keys(mcpServers).length === 0 ? (
                <div style={{ textAlign: 'center', padding: '20px 0', color: '#999' }}>
                  暂无配置的MCP服务器
                </div>
              ) : (
                <List
                  itemLayout="horizontal"
                  dataSource={Object.entries(mcpServers)}
                  renderItem={([key, server]) => (
                    <Collapse
                      bordered={false}
                      expandIcon={({ isActive }) => (
                        <CaretRightOutlined rotate={isActive ? 90 : 0} style={{ fontSize: '14px', marginTop: '10px' }} />
                      )}
                      style={{ marginBottom: 8, background: '#e8e8e8', borderRadius: 6 }}
                    >
                      <Collapse.Panel
                        key={key}
                        header={
                          <div style={{
                            display: 'flex',
                            alignItems: 'center',
                            width: '100%',
                            padding: '4px 0'
                          }}>
                            <div style={{ color: '#1890ff', fontSize: 16, marginRight: 12, display: 'flex', alignItems: 'center' }}>
                              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                                <path d="M9 11C8.44772 11 8 10.5523 8 10C8 9.44772 8.44772 9 9 9H15C15.5523 9 16 9.44772 16 10C16 10.5523 15.5523 11 15 11H9Z" fill="#1890ff" />
                                <path fillRule="evenodd" clipRule="evenodd" d="M7 5C5.34315 5 4 6.34315 4 8C4 9.65685 5.34315 11 7 11C7.35064 11 7.68722 10.9328 8 10.8102V13.1898C7.68722 13.0672 7.35064 13 7 13C5.34315 13 4 14.3431 4 16C4 17.6569 5.34315 19 7 19C8.65685 19 10 17.6569 10 16C10 14.3431 8.65685 13 7 13C6.64936 13 6.31278 13.0672 6 13.1898V10.8102C6.31278 10.9328 6.64936 11 7 11C8.65685 11 10 9.65685 10 8C10 6.34315 8.65685 5 7 5ZM6 8C6 7.44772 6.44772 7 7 7C7.55228 7 8 7.44772 8 8C8 8.55228 7.55228 9 7 9C6.44772 9 6 8.55228 6 8ZM6 16C6 15.4477 6.44772 15 7 15C7.55228 15 8 15.4477 8 16C8 16.5523 7.55228 17 7 17C6.44772 17 6 16.5523 6 16Z" fill="#1890ff" />
                                <path fillRule="evenodd" clipRule="evenodd" d="M17 5C15.3431 5 14 6.34315 14 8C14 9.65685 15.3431 11 17 11C17.3506 11 17.6872 10.9328 18 10.8102V13.1898C17.6872 13.0672 17.3506 13 17 13C15.3431 13 14 14.3431 14 16C14 17.6569 15.3431 19 17 19C18.6569 19 20 17.6569 20 16C20 14.3431 18.6569 13 17 13C16.6494 13 16.3128 13.0672 16 13.1898V10.8102C16.3128 10.9328 16.6494 11 17 11C18.6569 11 20 9.65685 20 8C20 6.34315 18.6569 5 17 5ZM16 8C16 7.44772 16.4477 7 17 7C17.5523 7 18 7.44772 18 8C18 8.55228 17.5523 9 17 9C16.4477 9 16 8.55228 16 8ZM16 16C16 15.4477 16.4477 15 17 15C17.5523 15 18 15.4477 18 16C18 16.5523 17.5523 17 17 17C16.4477 17 16 16.5523 16 16Z" fill="#1890ff" />
                              </svg>
                            </div>
                            <div style={{ flex: 1 }}>
                              <div style={{ fontWeight: 'bold', color: '#1890ff', fontSize: '14px' }}>{key}</div>
                            </div>
                            <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>



                              {/* 启用/禁用开关 */}
                              <div onClick={(e) => e.stopPropagation()}>
                                <Switch
                                  size="small"
                                  checked={!server.disabled}
                                  onChange={(checked) => {
                                    toggleServerDisabled(key, !checked);
                                  }}
                                  title={server.disabled ? "启用服务器" : "禁用服务器"}
                                />
                              </div>

                              {/* 删除按钮 */}
                              <Button
                                type="text"
                                danger
                                icon={<CloseOutlined />}
                                onClick={(e) => {
                                  e.stopPropagation();
                                  handleDeleteMcp(key);
                                }}
                                style={{ padding: '0 4px', height: '24px' }}
                              >
                                删除
                              </Button>
                            </div>
                          </div>
                        }
                        style={{ borderRadius: 6, marginBottom: 0 }}
                        className="mcp-server-item"
                      >
                        <div style={{ padding: '8px 0 8px 30px' }}>
                          <div style={{ marginBottom: 8 }}>
                            <span style={{ fontWeight: 'bold', marginRight: 8 }}>服务器名称:</span>
                            <span>{key}</span>
                          </div>
                          <div style={{ marginBottom: 8 }}>
                            <span style={{ fontWeight: 'bold', marginRight: 8 }}>工具类型:</span>
                            <span>{server.type}</span>
                          </div>
                          <div>
                            <span style={{ fontWeight: 'bold', marginRight: 8 }}>URL:</span>
                            <span style={{ wordBreak: 'break-all' }}>{server.url}</span>
                          </div>
                        </div>
                      </Collapse.Panel>
                    </Collapse>
                  )}
                />
              )}
              <div style={{ textAlign: 'right', marginTop: 24 }}>
                <Button onClick={handleMcpModalClose}>
                  关闭
                </Button>
              </div>
            </div>
          </Tabs.TabPane>
        </Tabs>
      </Modal>

      {/* 图片预览组件 */}
      <ImageViewer
        visible={previewState.visible}
        onClose={closePreview}
        images={previewState.images}
        activeIndex={previewState.activeIndex}
      />
    </div>
  );
};

export default AiChat;
